#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <time.h>          // Needed for time_t
#include <psapi.h>         // Needed for EnumProcess
#include "MCE.h"

//================================================================================================================================
// MCE_dll Global values
//================================================================================================================================

static char display_line_1[256];          // Top line for display 
static char display_line_2[256];          // Bottom line for display
static char last_display_line_1[256];     // Top line for display 
static char last_display_line_2[256];     // Bottom line for display
static char tag_value[80];                // tag value for return to dll call

typedef BOOL (WINAPI *QUERYFULLPROCESSIMAGENAME) (HANDLE hProcess, DWORD dwFlags, LPTSTR lpExeName, PDWORD lpdwSize);
QUERYFULLPROCESSIMAGENAME QueryFullProcessImageName;

//================================================================================================================================
// function to return bars  
//================================================================================================================================
void Tbars(unsigned char *line, int val1, int val2, int bchar)
{ int j;
  long int i;
  unsigned char c;

  i=val1; i=i*16; i=i/val2;
  for (j=0; j<16; j++) line[j]='_';
  for (j=0; j<i; j++) { c=bchar; line[j]=c; }
  line[16]=0;                
}

// function to return two time strings or bars  
//==========================================================================================================================

//================================================================================================================================
void Ttime_fmt(char *line,char *fmt, int tag1, int tag2)
{ 
  if (geti(TAG_UseBars)!=0) Tbars(line,geti(tag1),geti(tag2),geti(TAG_UseBars));
  else sprintf(line,fmt,gett(tag1),gett(tag2)); 
}


//================================================================================================================================
// external function for LCDSmartie dll - returns my first display line   
//================================================================================================================================
extern char * __stdcall MCE_dll_getvals1() 
{ 
  time_t time_since;
  struct tm * cur_time;
  int active;
  char str[256];
   
  time( &time_since );                    // get the time 
  cur_time =localtime( &time_since );     // convert to local time
        
  MCE_dll_getvals();                      // Get the tag values for the two lines

  active=1;
  if (geti(TAG_RecordingStatus)>0)  // Override with recording info if we are recording
      {if (geti(TAG_RecordingDepth)>1)
         { sprintf(display_line_1,"%s[%d] Ch%d %s",getdisplay(TAG_Record),geti(TAG_RecordingDepth),
                                        geti(TAG_RecordingTrackNumber),getst(TAG_RecordingChannelName)); }
        else { sprintf(display_line_1,"%s Ch%d %s",getdisplay(TAG_Record),
                                        geti(TAG_RecordingTrackNumber),getst(TAG_RecordingChannelName)); }
        sprintf(display_line_2,"%s",getst(TAG_RecordingMediaName));
      }
  else if (((active=MCE_dll_check_process("ehshell.exe"))==0)
             && (geti(TAG_IPRemote)==0)) // If Media centre is not running and running locally display something else  
      { strcpy(display_line_1,getdisplay(TAG_Windows7HTPC));
        strftime(display_line_2, sizeof display_line_2, getst(TAG_DateFormat), cur_time );
      }
  else if (getbi(TAG_DiscWriter_Start))  // Override with Disc writing info if we are burning
      {strcpy(display_line_1,getdisplay(TAG_BurningDisc));
        if (geti(TAG_UseBars)!=0)
           { Tbars(display_line_2,geti(TAG_DiscWriter_ProgressPercentageChanged),100,geti(TAG_UseBars)); }
        else sprintf(display_line_2,"%3d%%",geti(TAG_DiscWriter_ProgressPercentageChanged));
        // I could probably display current time/estimated time here if required.
      }
  else if (geti(TAG_StatusCounter)>0)  // If we are counting down an event (Play,stop,mute,volume etc.
      { //puti(TAG_StatusCounter,geti(TAG_StatusCounter)-1); Counted down elsewhere
        strcpy(display_line_1,getdisplay(geti(TAG_Mode)));
        if(geti(TAG_Mode)==TAG_Volume)
          { if (geti(TAG_VolumeCharacter)!=0) Tbars(display_line_2,geti(TAG_Volume),50,geti(TAG_VolumeCharacter));
            else { sprintf(display_line_2,"%2d / 50",geti(TAG_Volume)); } }
      }
  else 
      { 
          switch (geti(TAG_Status))
            {
              case TAG_Radio: 
              case TAG_TVTuner:
              case TAG_CD:
              case TAG_StreamingContentAudio:
              case TAG_StreamingContentVideo:
              case TAG_PVR:
              case TAG_Photos:
                   break;                                  // these get the stuff from the session
              default:
                   if (getbi(TAG_Play)==0)
                     { strcpy(display_line_1,getst(TAG_Status));
                       strftime(display_line_2, sizeof display_line_2, getst(TAG_DateFormat), cur_time );
                     }
            }
      }
//  if (active!=0) { MCE_check_for_reinit(); }Already done by check_counter
  if (geti(TAG_ModeVisible)!=0) 
    {
      if (geti(TAG_Mode)!=TAG_Volume) strcpy(str,getst(TAG_Icon)); else strcpy(str," ");
      strcat(str," ");
      strcat(str,display_line_1);
      strcpy(display_line_1,str);
    }
 
  return display_line_1;
}

//================================================================================================================================
// external function for LCDSmartie dll - returns the second display line   
//================================================================================================================================
extern char * __stdcall MCE_dll_getvals2() 
{ //MCE_dll_getvals(); 
  return display_line_2; 
}

//================================================================================================================================
// external function for LCDSmartie dll - returns the first display line based on session state 
// without recording, menu or Media Center active overrides
//================================================================================================================================
extern char * __stdcall MCE_dll_getvals11() 
{ MCE_dll_getvals(); return display_line_1; }



//================================================================================================================================
// external function for LCDSmartie dll - returns the second display line based on session status 
// without recording, menu or Media Center active overrides
//================================================================================================================================
extern char * __stdcall MCE_dll_getvals12() 
{ MCE_dll_getvals(); return display_line_2; }



//================================================================================================================================
// routine to get the display lines from the global tag table and status values using sessions
// These two lines are my interpretation of what I want on the display for each state
//================================================================================================================================
int MCE_dll_getvals() 
{
   time_t time_since;
   struct tm * cur_time;
   
   time( &time_since );   // get the time 
   cur_time =localtime( &time_since );  // convert to local time
   
   switch (geti(TAG_SessionValue))
   {
     case 0:                                                // Not in a session
          strcpy(display_line_1,getdisplay(TAG_MediaCenter));
          strftime(display_line_2, sizeof display_line_2, getst(TAG_DateFormat), cur_time );
          break;
     case TAG_Photos:
          strcpy(display_line_1,getdisplay(TAG_FS_Photos));  
          strcpy(display_line_2,getst(TAG_CurrentPicture));
          break;
     case TAG_PVR:
     case TAG_StreamingContentVideo:
          sprintf(display_line_1,"%s: %s",getdisplay(TAG_FS_Videos),getst(TAG_MediaName));
          Ttime_fmt(display_line_2,"%s/%s",TAG_TrackTime,TAG_MediaTime);
//          sprintf(display_line_2,"%s/%s",gett(TAG_TrackTime),gett(TAG_MediaTime)); 
          break;
     case TAG_CD:
          sprintf(display_line_1,"%s: %s:%s",getdisplay(TAG_CD),getst(TAG_ArtistName),getst(TAG_TrackName));
          Ttime_fmt(display_line_2,"%s/%s",TAG_TrackTime,TAG_TrackDuration);
//          sprintf(display_line_2,"%s/%s",gett(TAG_TrackTime),gett(TAG_TrackDuration));
          break;
     case TAG_StreamingContentAudio:
          sprintf(display_line_1,"%s: %s:%s",getdisplay(TAG_FS_Music),getst(TAG_ArtistName),getst(TAG_TrackName));
//          sprintf(display_line_1,"%s: %s:%s",getst(TAG_NextSessionType),getst(TAG_ArtistName),getst(TAG_TrackName));
          Ttime_fmt(display_line_2,"%s/%s",TAG_TrackTime,TAG_TrackDuration);
//          sprintf(display_line_2,"%s/%s",gett(TAG_TrackTime),gett(TAG_TrackDuration));
          break;
     case TAG_Radio:
//          sprintf(display_line_1,"%s: %s",getdisplay(TAG_FS_Radio),getst(TAG_RadioFrequency));
          sprintf(display_line_1,"%s: %3.1fFM",getdisplay(TAG_FS_Radio),
                                    ((float)atoi(getst(TAG_RadioFrequency))/1000000.0F)); 
          if ((strncmp(getst(TAG_RadioChannel),getst(TAG_ChannelNotFound),7)))
              strftime(display_line_2, sizeof display_line_2, getst(TAG_DateFormat), cur_time );
          else 
              sprintf(display_line_2,"%s",getst(TAG_RadioChannel));
          break;
     case TAG_TVTuner:
          sprintf(display_line_1,"%s: Ch %d %s",getdisplay(TAG_FS_TV),geti(TAG_TrackNumber),
                                         MCE_dll_get_tvchannel(getst(TAG_TrackNumber)));
          sprintf(display_line_2,"%s",getst(TAG_MediaName));
          break;
     default:
          strcpy(display_line_1,getst(TAG_SessionStatus));
          strftime(display_line_2, sizeof display_line_2, getst(TAG_DateFormat), cur_time );
   }

  // Store the last lines if it has changed
  if ( (strlen(display_line_1)!=strlen(last_display_line_1)) || (strncmp(display_line_1,last_display_line_1,strlen(display_line_1))) )
    { Tlog("getvals - line 1",display_line_1); strcpy(last_display_line_1,display_line_1); }
  if ((strlen(display_line_2)!=strlen(last_display_line_2)) || (strncmp(display_line_2,last_display_line_2,strlen(display_line_2))) )
    { Tlog("getvals - line 2",display_line_2); strcpy(last_display_line_2,display_line_2); }
                   
    return(0);
}    
 


//================================================================================================================================
// Routine to return the value of the supplied tag
//================================================================================================================================
extern char * __stdcall MCE_dll_get_tag_value( char *line)
{
     int tag,len,found,tagtype,taglen;
     char str[10];

     found=0;
     // Search the table of tags for the one supplied
     for (tag=0; tag<NUM_MTAGS; tag++)
       { if (!strncmp(line,gettag(tag),getlength(tag)))
            { len=strlen(line); tagtype=gettype(tag); taglen=strlen(gettag(tag));
              if (len==taglen)
                { if (tagtype==MINT)      { sprintf(tag_value,"%d",geti(tag)); }
                  else if (tagtype==MSTR) { strcpy(tag_value,getst(tag)); }
                  else if (tagtype==MBOO) { strcpy(tag_value,getb(tag)); }
                  else if (tagtype==MTIM) { strcpy(tag_value,gett(tag)); }
                  else { printf("*** Tag data type not found *** %s\n",line); strcpy(tag_value,"Tag not found"); }
                  if (tag==TAG_SessionType)           // Check for Session tag
                    { if (!strncmp(tag_value," ",1)){ putst(tag,getst(TAG_NextSessionType)); } }
                  found=1; break;                      // Found the tag - exit the loop
                }
              else if ( (len==(taglen+1)) && (toupper(line[len-1])=='D'))  // It's got an extra D on the end so return the Description
                { strcpy(tag_value,getdisplay(tag)); found=1; break; }     // Found the tag - exit the loop
              else if ( (len==(taglen+1)) && (toupper(line[len-1])=='S'))  // It's got an extra S on the end so return the string
                { strcpy(tag_value,getst(tag)); found=1; break; }          // Found the tag - exit the loop
              else if ( (len==(taglen+1)) && (toupper(line[len-1])=='I'))  // It's got an extra I on the end so return the int
                { if ((tagtype==MBOO) || (tagtype==MTIM) || (tagtype==MSTR) || (tagtype==MINT) )
                     { sprintf(tag_value,"%d",geti(tag)); }   
                  else { printf("*** Tag data type not found *** %s\n",line); strcpy(tag_value,"Tag not found"); }
                  found=1; break;                      // Found the tag - exit the loop
                }
              else if ( ((len==(taglen+2)) && (toupper(line[len-2])=='I')) && ((line[len-1]>'0') && (line[len-1]<('9'+1))) )
                // It's got an extra Ix on the end so return the int in x width with leading spaces
                { if ((tagtype==MBOO) || (tagtype==MTIM) || (tagtype==MSTR) || (tagtype==MINT) )
                    { str[0]='%'; str[1]=line[len-1]; str[2]='d'; str[3]=0;
                      sprintf(tag_value,str,geti(tag));
                    }
                  else { printf("*** Tag data type not found *** %s\n",line); strcpy(tag_value,"Tag not found"); }
                  found=1; break;                      // Found the tag - exit the loop
                }
              else if ( ((len==(taglen+2)) && (toupper(line[len-2])=='Z')) && ((line[len-1]>'0') && (line[len-1]<('9'+1))) )
                // It's got an extra Zx on the end so return the int in x width with leading zeros
                { if ((tagtype==MBOO) || (tagtype==MTIM) || (tagtype==MSTR) || (tagtype==MINT) )
                    { str[0]='%'; str[1]='0'; str[2]=line[len-1]; str[3]='d'; str[4]=0;
                      sprintf(tag_value,str,geti(tag));
                    }
                  else { printf("*** Tag data type not found *** %s\n",line); strcpy(tag_value,"Tag not found"); }
                  found=1; break;                      // Found the tag - exit the loop
                }
             }
        }  // end of for loop
        
        // If we didn't find the tag then return the error message
        if (found==0) { printf("**** Failed to find tag %s\n",line);
                               strcpy(tag_value,"Unknown tag: ");
                               strcat(tag_value,line);
                             }
        return (tag_value);

}   

//================================================================================================================================
// Routine to return the value(s) of the supplied tag or 2 tags
//================================================================================================================================
extern char * __stdcall MCE_dll_get_tag_values( char *line1, char *line2)
{   
    char temp[256],temp2[256];
    
    if (strlen(line2)==0) return MCE_dll_get_tag_value(line1); 
    strcpy (temp,MCE_dll_get_tag_value(line1));
    strcpy (temp2,MCE_dll_get_tag_value(line2));
    if (strlen(temp2)>0)
      { strcat (temp,"-");
        strcat (temp,temp2);
      }
    strcpy (tag_value,temp);
    return (tag_value);
}

//================================================================================================================================
// Routine to check if the given process is active
//================================================================================================================================
extern int __stdcall MCE_dll_check_process(char *procname)
{
	char szProcessName[MAX_PATH] = {0};
	DWORD dwProcesses[1024], cbNeeded, cProcesses, dwFlags, dw;
	unsigned int i;
	char PIDbuf[10];
	char buf[256];
	int found,slen;

    found=0;
	if (!EnumProcesses(dwProcesses, sizeof(dwProcesses), &cbNeeded)) return -1;
	cProcesses = cbNeeded / sizeof(DWORD);
	for (i = 0; i < cProcesses; i++)
	{   if(dwProcesses[i] != 0)
		{   HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, dwProcesses[i]);
			if (NULL != hProcess)
			{  dwFlags=0;
			   cbNeeded=MAX_PATH;
			   // note that the Query function used here is the only one that works in win7 x64
               if (!QueryFullProcessImageName(hProcess, dwFlags, szProcessName, &cbNeeded))
                 { dw = GetLastError(); 
                   FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
                      NULL, dw, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) buf, 256, NULL );
                   sprintf(buf,"Error %d - %s\n",dw,buf); Tlog("check_process",buf);
                 }
               else
                 { slen=strlen(procname);
                   if (!strncmp(procname,&szProcessName[strlen(szProcessName)-slen],slen)) found=1;
                 }
			}
  			CloseHandle(hProcess);
		}
    }
	return found;
} 


